package cn.texous.demo.dmqs.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.type.ArrayType;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeBindings;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/***/
public class JsonUtils {

    private static TypeFactory TYPE_FACTORY = TypeFactory.defaultInstance();
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);
    private static ObjectMapper viceMapper;

    private JsonUtils() {
        throw new IllegalArgumentException("cannot construct the final class JsonUtils");
    }

    /***/
    public static String object2String(Object object, boolean prettyPrint) {
        StringWriter writer = new StringWriter();

        try {
            if (prettyPrint) {
                OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValue(writer, object);
            } else {
                OBJECT_MAPPER.writer().writeValue(writer, object);
            }
        } catch (Exception var4) {
            logger.error("将 object 转换为 json 字符串时发生异常", var4);
            var4.printStackTrace();
            return null;
        }

        return writer.toString();
    }

    public static String object2String(Object object) {
        return object2String(object, false);
    }

    /***/
    public static String object2StringFromCamelToUnderLine(Object object, boolean prettyPrint) {
        StringWriter writer = new StringWriter();

        try {
            if (prettyPrint) {
                viceMapper.writerWithDefaultPrettyPrinter().writeValue(writer, object);
            } else {
                viceMapper.writer().writeValue(writer, object);
            }
        } catch (Exception var4) {
            logger.error("将 object 转换为 json 字符串时发生异常", var4);
            var4.printStackTrace();
            return null;
        }

        return writer.toString();
    }

    public static String object2StringFromCamelToUnderLine(Object object) {
        return object2StringFromCamelToUnderLine(object, false);
    }

    /***/
    public static <T> T string2Object(String content, JavaType type) {
        try {
            return OBJECT_MAPPER.readValue(content, type);
        } catch (Exception var4) {
            FormattingTuple message = MessageFormatter
                    .format("将字符串[{}]转换为对象[{}]时出现异常",
                            new Object[]{content, type, var4});
            logger.error(message.getMessage(), var4);
            throw new RuntimeException(message.getMessage(), var4);
        }
    }

    public static <T> T string2Object(String content, Class<T> clz) {
        JavaType type = TypeFactory.defaultInstance().constructType(clz);
        return string2Object(content, type);
    }

    /***/
    public static <T> T string2ObjectFromUnderLineToCamel(String content, JavaType type) {
        try {
            return viceMapper.readValue(content, type);
        } catch (Exception var4) {
            FormattingTuple message = MessageFormatter
                    .format("将字符串[{}]转换为对象[{}]时出现异常",
                            new Object[]{content, type, var4});
            logger.error(message.getMessage(), var4);
            throw new RuntimeException(message.getMessage(), var4);
        }
    }

    public static <T> T string2ObjectFromUnderLineToCamel(String content, Class<T> clz) {
        JavaType type = TypeFactory.defaultInstance().constructType(clz);
        return string2ObjectFromUnderLineToCamel(content, type);
    }

    /***/
    public static <K, V> Map<K, V> string2Map(String content, Class<K> kClass, Class<V> vClass) {
        MapType type = TypeFactory.defaultInstance()
                .constructMapType(HashMap.class, kClass, vClass);

        try {
            return (Map) OBJECT_MAPPER.readValue(content, type);
        } catch (Exception var6) {
            FormattingTuple message = MessageFormatter
                    .format("将字符串[{}]转换为Map时出现异常", content);
            logger.error(message.getMessage(), var6);
            throw new RuntimeException(message.getMessage(), var6);
        }
    }

    /***/
    public static Map<?, ?> string2Map(String content, JavaType keyType, JavaType valueType) {
        MapType type = TypeFactory.defaultInstance()
                .constructMapType(HashMap.class, keyType, valueType);

        try {
            return (Map) OBJECT_MAPPER.readValue(content, type);
        } catch (Exception var6) {
            FormattingTuple message = MessageFormatter
                    .format("将字符串[{}]转换为Map时出现异常", content);
            logger.error(message.getMessage(), var6);
            throw new RuntimeException(message.getMessage(), var6);
        }
    }

    /**
     * 将 JSON 格式的字符串转换为 map
     *
     * @param content content
     * @return
     */
    public static <T> Map<String, T> string2Map(String content) {
        JavaType type = TYPE_FACTORY.constructMapType(HashMap.class, String.class, Object.class);
        try {
            return OBJECT_MAPPER.readValue(content, type);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.format(
                    "将字符串[{}]转换为Map时出现异常", content);
            throw new RuntimeException(message.getMessage(), e);
        }
    }

    /***/
    public static <T> T[] string2Array(String content, Class<T> clz) {
        ArrayType type = ArrayType.construct(
                TypeFactory.defaultInstance().constructType(clz), (TypeBindings) null);

        try {
            return OBJECT_MAPPER.readValue(content, type);
        } catch (Exception var5) {
            FormattingTuple message = MessageFormatter
                    .format("将字符串[{}]转换为数组时出现异常", content);
            logger.error(message.getMessage(), var5);
            throw new RuntimeException(message.getMessage(), var5);
        }
    }

    /***/
    public static <C extends Collection<E>, E> C string2Collection(
            String content, Class<C> collectionType, Class<E> elementType) {
        try {
            JavaType type = TypeFactory.defaultInstance()
                    .constructCollectionType(collectionType, elementType);
            return OBJECT_MAPPER.readValue(content, type);
        } catch (Exception var5) {
            FormattingTuple message = MessageFormatter
                    .format("将字符串[{}]转换为集合[{}]时出现异常",
                            new Object[]{content, collectionType.getSimpleName(), var5});
            logger.error(message.getMessage(), var5);
            throw new RuntimeException(message.getMessage(), var5);
        }
    }

    /***/
    public static JsonNode toJsonNode(String content) {
        try {
            return OBJECT_MAPPER.readTree(content);
        } catch (Exception var3) {
            FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为JsonNode时出现异常", content);
            logger.error(message.getMessage(), var3);
            throw new RuntimeException(message.getMessage(), var3);
        }
    }

    public static String getString(JsonNode node, String fieldName, String defaultVal) {
        JsonNode fieldNode = node.get(fieldName);
        return fieldNode == null ? defaultVal : fieldNode.textValue();
    }

    public static String getString(JsonNode node, String fieldName) {
        return getString(node, fieldName, "");
    }

    public static boolean getBoolean(JsonNode node, String fieldName, boolean defaultVal) {
        JsonNode fieldNode = node.get(fieldName);
        return fieldNode == null ? defaultVal : fieldNode.booleanValue();
    }

    public static boolean getBoolean(JsonNode node, String fieldName) {
        return getBoolean(node, fieldName, false);
    }

    public static int getInt(JsonNode node, String fieldName, int defaultVal) {
        JsonNode fieldNode = node.get(fieldName);
        return fieldNode == null ? defaultVal : fieldNode.intValue();
    }

    public static int getInt(JsonNode node, String fieldName) {
        return getInt(node, fieldName, 0);
    }

    public static long getLong(JsonNode node, String fieldName, long defaultVal) {
        JsonNode fieldNode = node.get(fieldName);
        return fieldNode == null ? defaultVal : fieldNode.longValue();
    }

    public static long getLong(JsonNode node, String fieldName) {
        return getLong(node, fieldName, 0L);
    }

    public static double getDouble(JsonNode node, String fieldName, double defaultVal) {
        JsonNode fieldNode = node.get(fieldName);
        return fieldNode == null ? defaultVal : fieldNode.doubleValue();
    }

    public static double getDouble(JsonNode node, String fieldName) {
        return getDouble(node, fieldName, 0.0D);
    }

    public static BigDecimal getDecimal(JsonNode node, String fieldName, BigDecimal defaultVal) {
        JsonNode fieldNode = node.get(fieldName);
        return fieldNode == null ? defaultVal : fieldNode.decimalValue();
    }

    public static BigDecimal getDecimal(JsonNode node, String fieldName) {
        return getDecimal(node, fieldName, BigDecimal.ZERO);
    }

    public static BigInteger getBigInteger(JsonNode node, String fieldName, BigInteger defaultVal) {
        JsonNode fieldNode = node.get(fieldName);
        return fieldNode == null ? defaultVal : fieldNode.bigIntegerValue();
    }

    public static BigInteger getBigInteger(JsonNode node, String fieldName) {
        return getBigInteger(node, fieldName, BigInteger.ZERO);
    }

    /***/
    public static void writeJsonToFile(List<Map<String, Object>> rowList,
                                       String filePath) throws IOException {
        if (rowList != null && rowList.size() != 0) {
            String str = object2String(rowList);
            File file = new File(filePath);
            String encode = "UTF-8";
            FileUtils.writeStringToFile(file, str, encode);
        } else {
            File file = new File(filePath);
            String encode = "UTF-8";
            FileUtils.writeStringToFile(file, "[]", encode);
        }

    }

    static {
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        viceMapper = new ObjectMapper();
        viceMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        viceMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
    }


    /**
     * Returns object as JSON encoded string
     *
     * @param input the bean instance
     * @return Returns single line JSON string
     */
    public static String serialize(Object input) throws JsonProcessingException {
        return OBJECT_MAPPER.writeValueAsString(input);
    }

    /**
     * Returns JSON encoded string as real object
     *
     * @param input the encoded JSON string
     * @return Returns PoJo
     */
    public static <T> T deserialize(String input, Class<T> tClass) throws IOException {
        return OBJECT_MAPPER.readValue(input, tClass);
    }

}
